package com.ck.core.util;

import org.apache.commons.lang3.StringUtils;
import org.bytedeco.javacpp.opencv_core;
import org.bytedeco.javacpp.opencv_core.IplImage;
import org.bytedeco.javacv.FFmpegFrameGrabber;
import org.bytedeco.javacv.Frame;
import org.bytedeco.javacv.Java2DFrameConverter;
import org.bytedeco.javacv.OpenCVFrameConverter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

/**
 * 视频工具类
 *
 * @author linqiang
 * @date 2018-07-11 14:31
 */
public class VideoUtils {
    private static final Logger logger = LoggerFactory.getLogger(VideoUtils.class);
    public static final String IMG_TYPE_JPG = "jpg";
    public static final String IMG_TYPE_PNG = "png";

    /**
     * 随机从视频中采集一张图片保存到指定路径
     * 支持视频类型： mov,mp4,m4a,3gp,3g2,mj2
     *
     * @param videoPath      视频源地址, 如：D:\\test.MP4
     * @param targetFilePath 图片保存地址, 如D:\\img
     * @param targetFileName 图片保存名称, 如：aaa
     * @param imageType      图片类型（jpg, gif, png, jpeg）,默认jpg
     * @return 图片保存路径，如: D:\\img\aaa.jpg
     * @throws Exception
     */
    public static String randomGrabberImage(String videoPath, String targetFilePath, String targetFileName, String imageType, int index)
            throws Exception {
        try( FFmpegFrameGrabber ff = FFmpegFrameGrabber.createDefault(videoPath)) {
            Frame f = getFrame(ff, index);
            return doExecuteFrame(f, targetFilePath, targetFileName, imageType);
        }catch (Exception e) {
            logger.error(e.getMessage(),e);
            return null;
        }
    }


    /**
     * 从视频中采集最后一帧图片保存到指定路径
     * 支持视频类型： mov,mp4,m4a,3gp,3g2,mj2
     *
     * @param videoPath      视频源地址, 如：D:\\test.MP4
     * @param targetFilePath 图片保存地址, 如D:\\img
     * @param targetFileName 图片保存名称, 如：aaa
     * @param imageType      图片类型（jpg, gif, png, jpeg）,默认jpg
     * @return 图片文件
     * @throws Exception
     */
    public static File lastGrabberImageReturnFile(String videoPath, String targetFilePath, String targetFileName, String imageType)
            throws Exception {
        return randomGrabberImageReturnFile(videoPath, targetFilePath, targetFileName, imageType, Integer.MAX_VALUE);
    }

    /**
     * 从视频中采集最后一帧图片保存到指定路径
     * 支持视频类型： mov,mp4,m4a,3gp,3g2,mj2
     *
     * @param videoPath      视频源地址, 如：D:\\test.MP4
     * @param targetFilePath 图片保存地址, 如D:\\img
     * @param targetFileName 图片保存名称, 如：aaa
     * @param imageType      图片类型（jpg, gif, png, jpeg）,默认jpg
     * @return 图片文件
     * @throws Exception
     */
    public static File firstGrabberImageReturnFile(String videoPath, String targetFilePath, String targetFileName, String imageType)
            throws Exception {
        return randomGrabberImageReturnFile(videoPath, targetFilePath, targetFileName, imageType, 0);
    }

    /**
     * 从视频中采集指定位置帧图片保存到指定路径
     * 支持视频类型： mov,mp4,m4a,3gp,3g2,mj2
     *
     * @param videoPath      视频源地址, 如：D:\\test.MP4
     * @param targetFilePath 图片保存地址, 如D:\\img
     * @param targetFileName 图片保存名称, 如：aaa
     * @param imageType      图片类型（jpg, gif, png, jpeg）,默认jpg
     * @param index          指定位置，如果大于最后一帧默认取最后一帧(从0开始)
     * @return 图片文件
     * @throws Exception
     */
    public static File randomGrabberImageReturnFile(String videoPath, String targetFilePath, String targetFileName, String imageType, int index)
            throws Exception {
        File file ;
        try (FFmpegFrameGrabber ff = FFmpegFrameGrabber.createDefault(videoPath)) {


            ff.start();
            String rotate = ff.getVideoMetadata("rotate");
        //    Frame f = getFrame(ff,index);
            Frame f = null;
            int i = 0;
            int b = 0;
            int length = ff.getLengthInFrames();
            if (index == 0) {
                while (i < length) {
                    f = ff.grabFrame();
                    if (f != null && f.image != null) {
                       break;
                    } else {
                        System.out.println("第" + i + "帧为空");
                    }
                    i++;
                }
            }else{
                if (index > length) {
                    Frame fTemp;
                    while (i < length) {
                        fTemp = ff.grabImage();
                        if (fTemp == null || fTemp.image == null) {
                            break;
                        }
                        f = fTemp.clone();
                        i++;
                    }

                }

            }

            if (null != rotate && rotate.length() > 1) {
                OpenCVFrameConverter.ToIplImage converter = new OpenCVFrameConverter.ToIplImage();
                IplImage src = converter.convert(f);
                f = converter.convert(rotate(src, Integer.valueOf(rotate)));

            }
            file = doExecuteFrameReturnFile(f, targetFilePath, targetFileName, imageType);
        }
        return file;
    }

    /**
     * 获取指定位置帧
     *
     * @param ff    视频帧集合
     * @param index 如果大于最后一帧默认取最后一帧(从0开始)
     * @return
     * @throws Exception
     */
    private static Frame getFrame(FFmpegFrameGrabber ff, int index) throws Exception {
        ff.start();
        Frame f = null;
        int i = 0;
        int length = ff.getLengthInFrames();
        if (index == 0) {
            while (i < length) {
                f = ff.grabFrame();
                if (f != null && f.image != null) {
                    return f;
                } else {
                    System.out.println("第" + i + "帧为空");
                }
                i++;
            }
        }
        if (index > length) {
            Frame fTemp = null;
            while (i < length) {
                fTemp = ff.grabImage();
                if (fTemp == null || fTemp.image == null) {
                    break;
                }
                f = fTemp.clone();
                i++;
            }
            return f;
        }
        while (i < length) {
            f = ff.grabFrame();
            if (i == index) {
                break;
            }
            i++;
        }
        ff.stop();
        return f;
    }

    /**
     * 选择角度
     *
     * @param src   视频资源
     * @param angle 角度
     * @return
     */
    public static IplImage rotate(IplImage src, int angle) {
        IplImage img = IplImage.create(src.height(), src.width(), src.depth(), src.nChannels());
        opencv_core.cvTranspose(src, img);
        opencv_core.cvFlip(img, img, angle);
        return img;
    }

    /**
     * 写图片
     *
     * @param f              图片源
     * @param targetFilePath 图片保存地址
     * @param targetFileName 图片名称
     * @param imageType      图片类型（jpg, gif, png, jpeg）
     */
    private static String doExecuteFrame(Frame f, String targetFilePath, String targetFileName, String imageType) {
        if (null == f || null == f.image) {
            return "";
        }
        Java2DFrameConverter converter = new Java2DFrameConverter();
        if (StringUtils.isBlank(imageType)) {
            imageType = IMG_TYPE_JPG;
        }
        String fileUrl = targetFilePath + File.separator + targetFileName + "." + imageType;
        BufferedImage bi = converter.getBufferedImage(f);
        File output = new File(fileUrl);
        try {
            ImageIO.write(bi, imageType, output);
            return fileUrl;
        } catch (IOException e) {
           logger.error(e.getMessage(),e);
        }
        return "";
    }


    /**
     * 写图片
     *
     * @param f              图片源
     * @param targetFilePath 图片保存地址
     * @param targetFileName 图片名称
     * @param imageType      图片类型（jpg, gif, png, jpeg）
     */
    private static File doExecuteFrameReturnFile(Frame f, String targetFilePath, String targetFileName, String imageType) {
        if (null == f || null == f.image) {
            return null;
        }
        if (StringUtils.isBlank(imageType)) {
            imageType = IMG_TYPE_JPG;
        }
        Java2DFrameConverter converter = new Java2DFrameConverter();
        String fileUrl = targetFilePath + File.separator + targetFileName + "." + imageType;
        BufferedImage bi = converter.getBufferedImage(f);
        File output = new File(fileUrl);
        try {
            ImageIO.write(bi, imageType, output);
        } catch (IOException e) {
           logger.error(e.getMessage(),e);
        }
        return output;
    }

    public static void main(String[] args) throws Exception {
        lastGrabberImageReturnFile("D:\\1.mp4", "D:\\", "1", null);
    }
}